﻿using System;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.Windows.Input;
using System.Diagnostics;

namespace MoviePlayer.User_Controls
{

    /// <summary>
    /// Simple Movie Control class
    /// </summary>
    public partial class MovieControls : UserControl
    {
        private bool _invalidURL = false;
        public Visibility InvalidURL
        {
            get
            {
                return _invalidURL ? Visibility.Visible : Visibility.Collapsed;
            }
            set
            {
                if ((Visibility)value == Visibility.Collapsed)
                    _invalidURL = false;
                else
                    _invalidURL = true;
            }
        }

        public Visibility IsPlaying
        {
            get
            {
                return isPlaying ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        private Uri _movieURL;
        public string MovieURL
        {
            get 
            {
                if (!(_movieURL == null))
                {
                    return _movieURL.ToString();
                }
                return "";
            }
            set 
            {
                if (Uri.IsWellFormedUriString(value, UriKind.Absolute))
                {
                    _movieURL = new Uri(value);
                    _invalidURL = false;
                }
                else
                {
                    _invalidURL = true;
                }
            }
        }

        //create an event
        public event EventHandler FullScreen;

        private bool _isFullScreen;
        public bool IsFullScreen
        {
            get { return _isFullScreen; }
            set
            {
                _isFullScreen = value;
                this.FullScreen(this, new EventArgs());
            }
        }

        private Boolean _autoPlay;
        public Boolean AutoPlay
        {
            get { return _autoPlay; }
            set { _autoPlay = value; }
        }

        /// <summary>
        /// Initialize the movie control
        /// </summary>
        public MovieControls()
        {
            InitializeComponent();
            this.FullScreen += new EventHandler(MovieControls_FullScreen);
        }

        void MovieControls_FullScreen(object sender, EventArgs e)
        {
            //Change the control based on IsFullScreen
            if (!IsFullScreen)
            {
                Button_Exit_Full_Screen.Visibility = Visibility.Collapsed;
                Button_Full_Screen.Visibility = Visibility.Visible;
            }
        }

        private bool isPlaying = false;
        private bool wasPlaying = false;

        /// <summary>
        /// Private event handler for when the Play/Pause button is clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Play_Click(object sender, RoutedEventArgs e)
        {
            if (isPlaying == false)
            {
                Play();
            }
            else
            {
                Pause();
            }
        }

        public void Play()
        {
            //make sure the movie starts from the time on the slider
            SSMediaElement.Position = TimeSpan.FromSeconds(PositionSlider.Value);
            this.SSMediaElement.Play();
            this.Button_Play.Visibility = Visibility.Collapsed;
            this.Button_Pause.Visibility = Visibility.Visible;
            this.PauseImage.Visibility = Visibility.Collapsed;
            wasPlaying = isPlaying;
            isPlaying = true;
        }

        /// <summary>
        /// Pause the video whether it is playing or not
        /// </summary>
        public void Pause()
        {
            this.SSMediaElement.Pause();
            this.Button_Play.Visibility = Visibility.Visible;
            this.Button_Pause.Visibility = Visibility.Collapsed;
            this.PauseImage.Visibility = Visibility.Visible;
            wasPlaying = isPlaying;
            isPlaying = false;
        }

        /// <summary>
        /// Event fired when the Media is opened
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SSMediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            PositionSlider.Maximum = SSMediaElement.EndPosition.TotalSeconds;
            PositionSlider.SmallChange = PositionSlider.Maximum / 100;
            PositionSlider.LargeChange = PositionSlider.Maximum / 10;
            PositionText.Text = new StringBuilder(SSMediaElement.Position.ToString() + "|" + SSMediaElement.EndPosition.Hours.ToString("00") + ":" + SSMediaElement.EndPosition.Minutes.ToString("00") + ":" + SSMediaElement.EndPosition.Seconds.ToString("00")).ToString();
        }

        /// <summary>
        /// Event fired after the movie gets to the end
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SSMediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            ResetMedia();
        }

        private void ResetMedia()
        {
            this.SSMediaElement.Stop();
            //set the slider back to the start
            PositionSlider.Value = 0;
            this.Button_Play.Visibility = Visibility.Visible;
            this.Button_Pause.Visibility = Visibility.Collapsed;
            this.PauseImage.Visibility = Visibility.Visible;
            isPlaying = false;
        }

        /// <summary>
        /// Event fired if the media fails
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SSMediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            _invalidURL = true;
        }

        /// <summary>
        /// Private event handler for when the stop button is pressed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Stop_Click(object sender, RoutedEventArgs e)
        {
            ResetMedia();
        }

        private void SSMediaElement_Loaded(object sender, RoutedEventArgs e)
        {
            //this.SSMediaElement.SmoothStreamingSource = _movieURL;
            //SSMediaElement.AutoPlay = _autoPlay;
            if (_autoPlay)
            {
                isPlaying = true;
                this.Button_Play.Visibility = Visibility.Collapsed;
                this.Button_Pause.Visibility = Visibility.Visible;
                this.PauseImage.Visibility = Visibility.Collapsed;
                //Only hide the controls if autoplay is true
                HideControls.Stop();
                HideControls.Begin();
            }
            else
            {
                isPlaying = false;
                this.Button_Play.Visibility = Visibility.Visible;
                this.Button_Pause.Visibility = Visibility.Collapsed;
                this.PauseImage.Visibility = Visibility.Visible;
            }
        }

        private void PositionSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            //if the new value is more than the old value plus or minus the small change value then update the position because the handle was moved by the user
            if ((e.NewValue > e.OldValue + PositionSlider.SmallChange) || (e.NewValue < e.OldValue - PositionSlider.SmallChange))
            {
                UpdatePosition();
            }
            PositionText.Text = new StringBuilder(SSMediaElement.Position.Hours.ToString("00") + ":" + SSMediaElement.Position.Minutes.ToString("00") + ":" + SSMediaElement.Position.Seconds.ToString("00") + "|" + SSMediaElement.EndPosition.Hours.ToString("00") + ":" + SSMediaElement.EndPosition.Minutes.ToString("00") + ":" + SSMediaElement.EndPosition.Seconds.ToString("00")).ToString();
        }

        private void PositionSlider_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UpdatePosition();
        }

        //function to update the position of the movie based on the slider and reactivate the binding with the slider
        private void UpdatePosition()
        {
            //PositionText.Foreground = new SolidColorBrush(Colors.Purple);
            SSMediaElement.Position = TimeSpan.FromSeconds(PositionSlider.Value);
            //if the slider was moved by the user, recreate the binding to the media element
            Binding binding = new Binding("Position.TotalSeconds");
            binding.Source = SSMediaElement;
            binding.Mode = BindingMode.OneWay;
            PositionSlider.SetBinding(Slider.ValueProperty, binding);
            if (wasPlaying)
            {
                Play();
            }
        }

        private void Button_Full_Screen_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Host.Content.IsFullScreen = true;
            if (wasPlaying)
            {
                Play();
            }
            Button_Full_Screen.Visibility = Visibility.Collapsed;
            Button_Exit_Full_Screen.Visibility = Visibility.Visible;
            HideControls.Stop();
            HideControls.Begin();
        }

        private void Button_Exit_Full_Screen_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Host.Content.IsFullScreen = false;
            if (wasPlaying)
            {
                Play();
            }
            Button_Exit_Full_Screen.Visibility = Visibility.Collapsed;
            Button_Full_Screen.Visibility = Visibility.Visible;
        }

        private void LayoutRoot_MouseEnter(object sender, MouseEventArgs e)
        {
            if (!App.Current.Host.Content.IsFullScreen)
            {
                ShowControls.Stop();
                ShowControls.Begin();
            }
            //ControlPanel.Visibility = Visibility.Visible;
        }

        private void LayoutRoot_MouseLeave(object sender, MouseEventArgs e)
        {
            HideControls.Stop();
            HideControls.Begin();
            //ControlPanel.Visibility = Visibility.Collapsed;
        }

        private void ControlPanel_MouseEnter(object sender, MouseEventArgs e)
        {
            ShowControls.Stop();
            ShowControls.Begin();
        }

        private void ControlPanel_MouseLeave(object sender, MouseEventArgs e)
        {
            HideControls.Stop();
            HideControls.Begin();
        }

        private void SSMediaElement_LostFocus(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("SSMediaElement Lost Focus");
            Pause();
        }

        private void Element_LostFocus(object sender, RoutedEventArgs e)
        {
            object objectInFocus = System.Windows.Input.FocusManager.GetFocusedElement();

            if (!IsRelated(objectInFocus, sender))
            {
                Pause();
                Debug.WriteLine("Movie Paused by " + sender.GetType().FullName);
            }
            Debug.WriteLine(sender.GetType().FullName + " lost Focus to " + objectInFocus.GetType().FullName);
            Element_GotFocus(objectInFocus, e);
        }

        private bool IsRelated(object child, object parent)
        {
            return (child == parent) || ((child is FrameworkElement) && IsRelated(((FrameworkElement)child).Parent, parent));
        }

        private void Element_GotFocus(object sender, RoutedEventArgs e)
        {
            String name = "not a control";
            if (sender is Control)
            {
                name = ((Control)sender).Name;
            }
            Debug.WriteLine(sender.GetType().FullName + ": " + name + " is in Focus");
        }
    }
}
